package com.dingup.paike.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingup.paike.model.pk.PkLessonInfo;
import com.suyeer.basic.util.BDateUtil;
import com.suyeer.basic.util.BEncryptUtil;
import com.suyeer.basic.util.BHttpResUtil;
import com.suyeer.basic.util.BLogUtil;
import org.apache.commons.io.IOUtils;

import java.io.DataInputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.dingup.paike.util.ConstUtil.*;

/**
 * @author jun 2018/10/25
 */
public class EEOUtil {
    private final static String COURSE_URL = "http://www.eeo.cn/partner/api/course.api.php?action=";
    private final static String CLOUD_URL = "http://www.eeo.cn/partner/api/cloud.api.php?action=";
    private final static String IMG_URL = "http://onlinetest-public.oss-cn-beijing.aliyuncs.com/manage_center/class_img.png";
    private final static String DEFAULT_PASSWORD = "dingshang123";
    private final static int CODE_SUCCESS = 1;
    private final static int CODE_STUDENT = 1;
    private final static int CODE_OBSERVER = 2;
    private final static int CODE_NO_REGISTER = 0;
    private final static int CODE_ON = 1;
    private final static int CODE_OFF = 0;
    private final static int CODE_TEL_NUM_ALREADY_REGISTER = 135;
    private final static int CODE_COURSE_HAVE_SAME_STUDENT = 163;
    private final static int CODE_COURSE_HAVE_SAME_OBSERVER = 164;
    private final static int CODE_CLASS_HAVE_SAME_STUDENT = 166;
    private final static String BOUNDARY = "----MyFormBoundarySMFEtUYQG6r5B920";

    /**
     * 注册用户到EEO
     *
     * @param userMobilePhone String
     * @return JSONObject
     * @throws Exception Exception
     */
    public static JSONObject register(String userMobilePhone) throws Exception {
        JSONObject params = new JSONObject();
        params.put(KEY_TELEPHONE, userMobilePhone);
        params.put(KEY_PASSWORD, DEFAULT_PASSWORD);
        JSONObject result = sendRequestToEeo(params, EEO_REGISTER);
        printLogger(result, EEO_REGISTER, params);
        // check result
        if (result == null) {
            throw new Exception("调用EEO接口失败");
        }
        int errNo = result.getJSONObject(KEY_ERROR_INFO).getIntValue(KEY_ERRNO);
        if (errNo != CODE_SUCCESS && errNo != CODE_TEL_NUM_ALREADY_REGISTER) {
            throw new Exception(result.getJSONObject(KEY_ERROR_INFO).getString(KEY_ERROR));
        }
        return result;
    }

    /**
     * 注册老师
     *
     * @param userName        String
     * @param userMobilePhone String
     */
    public static void registerTeacher(String userName, String userMobilePhone) {
        JSONObject params = new JSONObject();
        params.put(KEY_TEACHER_ACCOUNT, userMobilePhone);
        params.put(KEY_TEACHER_NAME, userName);
        JSONObject result = sendRequestToEeo(params, EEO_ADD_TEACHER);
        EEOUtil.printLogger(result, EEO_ADD_TEACHER, params);
    }

    /**
     * 修改密码
     *
     * @param userMobilePhone String
     * @param password        String
     * @throws Exception Exception
     */
    public static void modifyPasswordByTel(String userMobilePhone, String password) throws Exception {
        JSONObject params = new JSONObject();
        params.put(KEY_TELEPHONE, userMobilePhone);
        params.put(KEY_PASSWORD, password);
        JSONObject result = EEOUtil.sendRequestToEeo(params, EEO_MODIFY_PASSWORD_BY_TELEPHONE);
        EEOUtil.checkEeoResult(result, EEO_MODIFY_PASSWORD_BY_TELEPHONE, params);
    }

    /**
     * 添加班级, 并返回eeoCourseId
     *
     * @param className  String
     * @param folderId   String
     * @param expiryTime String
     * @return Integer
     * @throws Exception Exception
     */
    public static Integer addCourse(String className, String folderId, String expiryTime) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_NAME, className);
//        param.put(KEY_FOLDER_ID, folderId);
        param.put(KEY_FILE_DATA, IMG_URL);
        param.put(KEY_EXPIRY_TIME, expiryTime);
        JSONObject result = sendRequestToEeo(param, EEO_ADD_COURSE);
        EEOUtil.checkEeoResult(result, EEO_ADD_COURSE, param);
        return result.getInteger(KEY_DATA);
    }

    /**
     * 编辑班级
     *
     * @param className   String
     * @param folderId    String
     * @param expiryTime  String
     * @param eeoCourseId Integer
     * @throws Exception Exception
     */
    public static void editCourse(String className, String folderId, String expiryTime,
                                  Integer eeoCourseId) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, eeoCourseId);
        param.put(KEY_COURSE_NAME, className);
//        param.put(KEY_FOLDER_ID, folderId);
        param.put(KEY_EXPIRY_TIME, expiryTime);
        JSONObject result = sendRequestToEeo(param, EEO_EDIT_COURSE);
        EEOUtil.checkEeoResult(result, EEO_EDIT_COURSE, param);
    }

    /**
     * 删除班级
     *
     * @param eeoCourseId Integer
     * @throws Exception Exception
     */
    public static void delCourse(Integer eeoCourseId) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, eeoCourseId);
        JSONObject result = sendRequestToEeo(param, EEO_DEL_COURSE);
        EEOUtil.checkEeoResult(result, EEO_DEL_COURSE, param);
    }

    /**
     * 班级下添加学生或旁听
     *
     * @param studentArr  JSONArray
     * @param eeoCourseId Integer
     * @param identity    (identity Int 学生和旁听的识别: 1为学生,2为旁听)
     * @return String
     * @throws Exception Exception
     */
    public static String addCourseStudentMultiple(JSONArray studentArr, Integer eeoCourseId,
                                                  Integer identity) throws Exception {
        StringBuilder sb = new StringBuilder();
        try {
            if (studentArr.size() > 0) {
                JSONObject param = new JSONObject();
                param.put(KEY_COURSE_ID, eeoCourseId);
                param.put(KEY_IDENTITY, identity);
                param.put(KEY_IS_REGISTER, CODE_NO_REGISTER);
                param.put(KEY_STUDENT_JSON, studentArr);
                JSONObject result = sendRequestToEeo(param, EEO_ADD_COURSE_STUDENT_MULTIPLE);
                EEOUtil.printLogger(result, EEO_ADD_COURSE_STUDENT_MULTIPLE, param);
                sb.append(getMessage(result, studentArr, identity));
            }
        } catch (Exception e) {
            throw new Exception("添加学生到EEO失败");
        }
        return sb.toString();
    }

    /**
     * 添加课节, 并返回eeoLessonId
     *
     * @param tl             PkLessonInfo
     * @param eeoCourseId    Integer
     * @param teacherAccount String
     * @param teacherName    String
     * @return Integer
     * @throws Exception Exception
     */
    public static Integer addCourseClass(PkLessonInfo tl, Integer eeoCourseId, String teacherAccount,
                                         String teacherName) throws Exception {
        EEOUtil.deleteCourseStudent(eeoCourseId, teacherAccount, CODE_STUDENT);
        EEOUtil.deleteCourseStudent(eeoCourseId, teacherAccount, CODE_OBSERVER);
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, eeoCourseId);
        param.put(KEY_CLASS_NAME, tl.getLessonName());
        param.put(KEY_BEGIN_TIME, BDateUtil.getTimestampLong(tl.getBeginTime()));
        param.put(KEY_END_TIME, BDateUtil.getTimestampLong(tl.getEndTime()));
        param.put(KEY_TEACHER_ACCOUNT, teacherAccount);
        param.put(KEY_TEACHER_NAME, teacherName);
        param.put(KEY_SEAT_NUM, tl.getSeatNum());
        param.put(KEY_RECORD, tl.getIfTranscribe() ? CODE_ON : CODE_OFF);
        param.put(KEY_LIVE, tl.getIfLive() ? CODE_ON : CODE_OFF);
        param.put(KEY_REPLAY, tl.getIfPlayback() ? CODE_ON : CODE_OFF);
        JSONObject result = sendRequestToEeo(param, EEO_ADD_COURSE_CLASS);
        checkEeoResult(result, EEO_ADD_COURSE_CLASS, param);
        return result.getInteger(KEY_DATA);
    }

    /**
     * 编辑课节
     *
     * @param newTsl         PkLessonInfo
     * @param teacherAccount String
     * @param teacherName    String
     * @throws Exception Exception
     */
    public static void editCourseClass(PkLessonInfo newTsl, String teacherAccount,
                                       String teacherName) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, newTsl.getEeoCourseId());
        param.put(KEY_CLASS_ID, newTsl.getEeoLessonId());
        param.put(KEY_CLASS_NAME, newTsl.getLessonName());
        param.put(KEY_BEGIN_TIME, BDateUtil.getTimestampLong(newTsl.getBeginTime()));
        param.put(KEY_END_TIME, BDateUtil.getTimestampLong(newTsl.getEndTime()));
        param.put(KEY_TEACHER_ACCOUNT, teacherAccount);
        param.put(KEY_TEACHER_NAME, teacherName);
        param.put(KEY_RECORD, newTsl.getIfTranscribe() ? CODE_ON : CODE_OFF);
        param.put(KEY_LIVE, newTsl.getIfLive() ? CODE_ON : CODE_OFF);
        param.put(KEY_REPLAY, newTsl.getIfPlayback() ? CODE_ON : CODE_OFF);
        JSONObject result = sendRequestToEeo(param, EEO_EDIT_COURSE_CLASS);
        checkEeoResult(result, EEO_EDIT_COURSE_CLASS, param);
    }

    /**
     * 批量排课
     *
     * @param pkLessonInfoList List<PkLessonInfo>
     * @param eeoCourseId      Integer
     * @param teacherAccount   String
     * @param teacherName      String
     * @return JSONArray
     * @throws Exception Exception
     */
    public static JSONArray addCourseClassMultiple(List<PkLessonInfo> pkLessonInfoList,
                                                   Integer eeoCourseId,
                                                   String teacherAccount,
                                                   String teacherName) throws Exception {
        EEOUtil.deleteCourseStudent(eeoCourseId, teacherAccount, CODE_STUDENT);
        EEOUtil.deleteCourseStudent(eeoCourseId, teacherAccount, CODE_OBSERVER);
        JSONArray classJsonArr = new JSONArray();
        for (PkLessonInfo p : pkLessonInfoList) {
            JSONObject classJsonObj = new JSONObject();
            classJsonObj.put(KEY_CLASS_NAME, p.getLessonName());
            classJsonObj.put(KEY_BEGIN_TIME, BDateUtil.getTimestampLong(p.getBeginTime()));
            classJsonObj.put(KEY_END_TIME, BDateUtil.getTimestampLong(p.getEndTime()));
            classJsonObj.put(KEY_TEACHER_ACCOUNT, teacherAccount);
            classJsonObj.put(KEY_TEACHER_NAME, teacherName);
            classJsonObj.put(KEY_SEAT_NUM, p.getSeatNum());
            classJsonObj.put(KEY_RECORD, p.getIfTranscribe() ? CODE_ON : CODE_OFF);
            classJsonObj.put(KEY_LIVE, p.getIfLive() ? CODE_ON : CODE_OFF);
            classJsonObj.put(KEY_REPLAY, p.getIfPlayback() ? CODE_ON : CODE_OFF);
            classJsonArr.add(classJsonObj);
        }
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, eeoCourseId);
        param.put(KEY_CLASS_JSON, classJsonArr);
        JSONObject result = sendRequestToEeo(param, EEO_ADD_COURSE_CLASS_MULTIPLE);
        checkEeoResult(result, EEO_ADD_COURSE_CLASS_MULTIPLE, param);
        return result.getJSONArray(KEY_DATA);
    }

    /**
     * 编辑上台人数
     *
     * @param newTsl PkLessonInfo
     * @throws Exception Exception
     */
    public static void modifyClassSeatNum(PkLessonInfo newTsl) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, newTsl.getEeoCourseId());
        param.put(KEY_CLASS_ID, newTsl.getEeoLessonId());
        param.put(KEY_SEAT_NUM, newTsl.getSeatNum());
        JSONObject result = sendRequestToEeo(param, EEO_MODIFY_CLASS_SEAT_NUM);
        checkEeoResult(result, EEO_MODIFY_CLASS_SEAT_NUM, param);
    }

    /**
     * 获取课程直播/回放播放器地址, 本方法不需要验证EEO返回值
     *
     * @param pkLessonInfo PkLessonInfo
     */
    public static JSONObject getWebcastUrl(PkLessonInfo pkLessonInfo) {
        JSONObject result = null;
        try {
            JSONObject param = new JSONObject();
            param.put(KEY_COURSE_ID, pkLessonInfo.getEeoCourseId());
            param.put(KEY_CLASS_ID, pkLessonInfo.getEeoLessonId());
            result = sendRequestToEeo(param, EEO_GET_WEB_CAST_URL);
        } catch (Exception e) {
            BLogUtil.error(e);
        }
        return result;
    }

    /**
     * 获取课节直播流地址、回放视频地址,  本方法不需要验证EEO返回值
     *
     * @param pkLessonInfo PkLessonInfo
     */
    public static JSONObject getClassVideo(PkLessonInfo pkLessonInfo) {
        JSONObject result = null;
        try {
            JSONObject param = new JSONObject();
            param.put(KEY_CLASS_ID, pkLessonInfo.getEeoLessonId());
            param.put(KEY_COURSE_ID, pkLessonInfo.getEeoCourseId());
            result = sendRequestToEeo(param, EEO_GET_CLASS_VIDEO);
            if (result != null) {
                result.put("mp4List", getUrlList(result));
            }
        } catch (Exception e) {
            BLogUtil.error(e);
        }
        return result;
    }

    /**
     * 获取课节直播流地址、回放视频地址, 纯 mp4 地址,  本方法不需要验证EEO返回值
     *
     * @param pkLessonInfo PkLessonInfo
     */
    public static List<String> getClassVideoUrlList(PkLessonInfo pkLessonInfo) {
        List<String> retList = new ArrayList<>();
        JSONObject eeoObj = getClassVideo(pkLessonInfo);
        if (eeoObj != null && eeoObj.getJSONArray("mp4List") != null) {
            JSONArray mp4List = eeoObj.getJSONArray("mp4List");
            for (int i = 0; i < mp4List.size(); i++) {
                retList.add(mp4List.getString(i));
            }
        }
        return retList;
    }

    private static List<String> getUrlList(JSONObject obj) {
        List<String> urlList = new ArrayList<>();
        if (obj != null) {
            String str = JSON.toJSONString(obj);
            String[] strArr = str.split("\"");
            for (String s : strArr) {
                if (s.contains(".mp4")) {
                    urlList.add(s);
                }
            }
        }
        return urlList;
    }

    /**
     * @param pkLessonInfo PkLessonInfo
     * @return String
     * @throws Exception Exception
     */
    public static String getLoginLinked(PkLessonInfo pkLessonInfo, String telephone) throws Exception {
        if (pkLessonInfo == null || pkLessonInfo.getEeoLessonId() == null
                || pkLessonInfo.getEeoLessonId().intValue() == 0) {
            throw new Exception("当前课节非线上课");
        }
        JSONObject param = new JSONObject();
        param.put(KEY_TELEPHONE, telephone);
        param.put(KEY_COURSE_ID, pkLessonInfo.getEeoCourseId());
        param.put(KEY_CLASS_ID, pkLessonInfo.getEeoLessonId());
        JSONObject result = sendRequestToEeo(param, EEO_GET_LOGIN_LINKED);
        checkEeoResult(result, EEO_GET_LOGIN_LINKED, param);
        return result.getString(KEY_DATA);
    }

    /**
     * 删除班级下的学生
     *
     * @param courseId     Integer
     * @param studentId    String
     * @param identityCode int
     */
    public static void deleteCourseStudent(Integer courseId, String studentId, int identityCode) {
        List<String> studentList = new ArrayList<>();
        studentList.add(studentId);
        deleteCourseStudentMultiple(courseId, studentList, identityCode);
    }

    /**
     * 批量删除班级下的学生
     *
     * @param courseId     Integer
     * @param studentIds   List<String>
     * @param identityCode int
     */
    public static void deleteCourseStudentMultiple(Integer courseId, List<String> studentIds, int identityCode) {
        try {
            if (studentIds != null && studentIds.size() > 0) {
                JSONObject param = new JSONObject();
                JSONObject stu = new JSONObject();
                for (int i = 0; i < studentIds.size(); i++) {
                    stu.put(String.valueOf(i), studentIds.get(i));
                }
                param.put(KEY_IDENTITY, identityCode);
                param.put(KEY_COURSE_ID, courseId);
                param.put(KEY_STUDENT_JSON, stu);
                JSONObject result = sendRequestToEeo(param, EEO_DEL_COURSE_STUDENT_MULTIPLE);
                EEOUtil.printLogger(result, EEO_DEL_COURSE_STUDENT_MULTIPLE, param);
            }
        } catch (Exception e) {
            BLogUtil.error(e);
        }
    }

    private static String getMessage(JSONObject result, JSONArray userArr, Integer identity) throws Exception {
        StringBuilder sb = new StringBuilder();
        JSONArray dataArr = result.getJSONArray("data");
        if (dataArr.size() != userArr.size()) {
            sb.append("添加学生时EEO返回的数据缺失, 请到EEO网站检查此班级的学生.");
        } else {
            for (int i = 0; i < dataArr.size(); i++) {
                JSONObject eeoObj = dataArr.getJSONObject(i);
                JSONObject userObj = userArr.getJSONObject(i);
                int errno = eeoObj.getIntValue(KEY_ERRNO);
                if (errno != CODE_SUCCESS) {
                    boolean flag = (!((errno == CODE_COURSE_HAVE_SAME_STUDENT && identity == CODE_STUDENT)
                            || (errno == CODE_COURSE_HAVE_SAME_OBSERVER && identity == CODE_STUDENT)
                            || (errno == CODE_CLASS_HAVE_SAME_STUDENT && identity == CODE_OBSERVER)));
                    if (flag) {
                        sb.append(String.format("添加id'%s', 姓名'%s'的用户失败, EEO返回信息:%s\n",
                                userObj.getString(KEY_ACCOUNT),
                                userObj.getString(KEY_NAME),
                                eeoObj.getString(KEY_ERROR)));
                    }
                }
            }
        }
        return sb.toString();
    }

    public static JSONObject getCourseStudent(Integer courseId, Integer identity) throws Exception {
        JSONObject param = new JSONObject();
        param.put(KEY_COURSE_ID, courseId);
        param.put(KEY_IDENTITY, identity);
        return sendRequestToEeo(param, EEO_GET_COURSE_STUDENT);
    }


    /**
     * 发送包含文件的post请求, 只适用于排课系统与eeo接口对接;
     *
     * @param urlStr String
     * @param params JSONObject
     * @return JSONObject
     * @throws Exception Exception
     */
    private static JSONObject sendHttpFilePostRequest(String urlStr, JSONObject params) throws Exception {
        HttpURLConnection hc = null;
        String retStr = null;
        try {
            URL url = new URL(urlStr);
            hc = (HttpURLConnection) url.openConnection();
            hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            hc.setRequestProperty("Charsert", DEFAULT_ENCODE);
            hc.setDoOutput(true);
            hc.setDoInput(true);
            hc.setUseCaches(false);
            hc.setRequestMethod("POST");

            OutputStream outputStream = hc.getOutputStream();
            //1.先写文字形式的post流
            String boundary = BOUNDARY;
            StringBuffer resSB = new StringBuffer("\r\n");
            String endBoundary = "\r\n--" + boundary + "--\r\n";
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().toString();
                if (!key.equals(KEY_FILE_DATA)) {
                    resSB.append(String.format("Content-Disposition: form-data; name=%s\r\n\r\n%s\r\n--%s\r\n", key,
                            value, boundary));
                }
            }
            String boundaryMessage = resSB.toString();
            outputStream.write(("--" + boundary + boundaryMessage).getBytes(DEFAULT_ENCODE));
            //2.再写文件开式的post流
            resSB = new StringBuffer();
            resSB.append("Content-Disposition: form-data; name=Filedata; filename=class_img.jpg\r\nContent-Type: " +
                    "image/jpeg\r\n\r\n");
            outputStream.write(resSB.toString().getBytes(DEFAULT_ENCODE));
            URL fileUrl = new URL(params.getString(KEY_FILE_DATA));
            DataInputStream in = new DataInputStream(fileUrl.openConnection().getInputStream());
            outputStream.write(IOUtils.toByteArray(in));
            in.close();
            //3.最后写结尾
            outputStream.write(endBoundary.getBytes(DEFAULT_ENCODE));
            outputStream.close();
            retStr = IOUtils.toString(hc.getInputStream(), DEFAULT_ENCODE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (hc != null) {
                    hc.disconnect();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return JSONObject.parseObject(retStr);
    }

    /**
     * 排课--请求EEO接口
     *
     * @param param JSONObject
     * @param func  String
     * @return JSONObject
     */
    public static JSONObject sendRequestToEeo(JSONObject param, String func) {
        JSONObject result = new JSONObject();
        String url = (func.equals(EEO_GET_FOLDER_LIST) ? CLOUD_URL : COURSE_URL);
        try {
            // EEO的机构验证数据, 线上与本地不同
            String timeStampStr = BDateUtil.getTimestampString();
            param.put(KEY_SID, SYS_CONFIG_DATA.getEeoSid());
            param.put(KEY_TIME_STAMP, timeStampStr);
            param.put(KEY_SAFE_KEY, BEncryptUtil.MD5(SYS_CONFIG_DATA.getEeoSecret() + timeStampStr).toLowerCase());
            if (param.containsKey(KEY_FILE_DATA)) {
                result = sendHttpFilePostRequest(url + func, param);
            } else {
                result = BHttpResUtil.sendHttpPostRequest(url + func, param);
            }
        } catch (Exception e) {
            BLogUtil.error(e);
        }
        return result;
    }

    /**
     * 检查调用eeo接口是否成功
     *
     * @param resultObj JSONObject
     * @param method    String
     * @param params    JSONObject
     * @throws Exception Exception
     */
    public static void checkEeoResult(JSONObject resultObj, String method, JSONObject params) throws Exception {
        printLogger(resultObj, method, params);
        if (resultObj == null || resultObj.getJSONObject(KEY_ERROR_INFO) == null
                || resultObj.getJSONObject(KEY_ERROR_INFO).getInteger(KEY_ERRNO) == null) {
            throw new Exception("调用EEO接口失败");
        }
        if (resultObj.getJSONObject(KEY_ERROR_INFO).getIntValue(KEY_ERRNO) != CODE_SUCCESS) {
            throw new Exception(method + " : " + resultObj.toJSONString());
        }
    }

    private static void printLogger(JSONObject resultObj, String method, JSONObject params) {
        BLogUtil.info(String.format("请求EEO接口日志:\n接口名称: %s\n请求参数: %s\n返回结果: %s",
                method, JSON.toJSONString(params), JSON.toJSONString(resultObj)));
    }

}
